
package com.prm.extrader;

import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import com.pretty_tools.dde.client.DDEClientConversation;
import com.pretty_tools.dde.client.DDEClientException;
import com.pretty_tools.dde.client.DDEMLException;
import java.util.Map;
import java.util.TreeMap;

//import javax.xml.bind.DatatypeConverter;

/*
public static final byte[] intToByteArray(int value) {
    return new byte[] {
            (byte)(value >>> 24),
            (byte)(value >>> 16),
            (byte)(value >>> 8),
            (byte)value};
}
*/

interface ReplyInterface 
{
	public String reply_func(String rcvdStr);
}

class ReplyFunc implements ReplyInterface
{
	public String reply_func(String rcvdStr) {
		return new String("ID:" + JavaClientMain.getClientId() + " Received string: " + rcvdStr);
	}
}


class ExcelClient {
	private final DDEClientConversation conversation = new DDEClientConversation();
	private Map<String, ExcelTraderProtoBuf.Instrument> instMap = new TreeMap();
	private final int RowOffset=2;
	private final int ColOffset=2;

	public ExcelClient() {
        conversation.setTimeout(3000);
        try {
	        conversation.connect("Excel", "Sheet1");
		} catch (DDEMLException e) {
            System.out.println("DDEMLException: 0x" + Integer.toHexString(e.getErrorCode()) + " " + e.getMessage());
        } catch (DDEClientException e) {
            System.out.println("DDEClientException: " + e.getMessage());
        }
        
        sendDataToCell(RowOffset, ColOffset, "Feedcode");
        sendDataToCell(RowOffset, ColOffset+1, "Strike");
        sendDataToCell(RowOffset, ColOffset+2, "Kind");
        sendDataToCell(RowOffset, ColOffset+3, "Best Bid");
        sendDataToCell(RowOffset, ColOffset+4, "Best Ask");
	        
	}

	public void sendInstToExcel(ExcelTraderProtoBuf.InstArray instArray) {
		for (ExcelTraderProtoBuf.Instrument inst : instArray.getInstArrayList()) {
			instMap.put(inst.getFeedcode(), inst);
			// Let's print out all tree members at the moment for this prototype.
			// This will be later to be modified to print the changed instrument only.
			int i=1;
			for (Map.Entry<String, ExcelTraderProtoBuf.Instrument> entry : instMap.entrySet()) {
				sendDataToCell(RowOffset + i, ColOffset, entry.getKey());
				ExcelTraderProtoBuf.Instrument instEntry = (ExcelTraderProtoBuf.Instrument) entry.getValue();
				sendDataToCell(RowOffset + i, ColOffset+1, instEntry.getStrike());
				sendDataToCell(RowOffset + i, ColOffset+2, (instEntry.getIsCall()==true)? "Call" : "Put");
				sendDataToCell(RowOffset + i, ColOffset+3, instEntry.getBestBid());
				sendDataToCell(RowOffset + i, ColOffset+4, instEntry.getBestAsk());
				i++;
			}
		}
	}
	
	public void sendDataToCell(int row, int column, Object data) {
		String sndStr;
		if (data instanceof String) {
			sndStr = (String)data;
		} else {
			sndStr = String.valueOf(data);
		}
		String cellStr = new String("R" + String.valueOf(row) + "C" + String.valueOf(column));
		System.out.println("Constructed cellStr=" + cellStr);
		try {
			conversation.poke(cellStr, sndStr);
		} catch (DDEClientException e) {
            System.out.println("DDEClientException: " + e.getMessage());
        }
	}
	
	public void terminateDDEClient() {
		try {
			conversation.execute("[close()]");
		} catch (DDEClientException e) {
            System.out.println("DDEClientException: " + e.getMessage());
        }
	}
	
	
}

class RxThread extends Thread {
	private Socket mySock;
	private int client_id;
	private DataInputStream is=null;
	private DataOutputStream os=null;
	private ReplyInterface reply_cb;
	private ExcelClient exClient;

	public RxThread(Socket mySock, int client_id, ReplyInterface cb) {
		this.mySock = mySock;
		this.client_id = client_id;
		this.reply_cb = cb;
	}

	public void run() {
		try {
			is = new DataInputStream(mySock.getInputStream());
			os = new DataOutputStream(mySock.getOutputStream());
			exClient = new ExcelClient();
		} catch (IOException e) {
			System.err.println("Creating DataStream Error.");
		}

		try {
			while(true) {
				System.out.println("Waiting for data from the server...");
				int len = is.readInt();
				
				System.out.println("Received len=" + len);
				byte[] buf = new byte[len];
				is.readFully(buf);
				ExcelTraderProtoBuf.InstArray inst_array = ExcelTraderProtoBuf.InstArray.parseFrom(buf);
				System.out.println(inst_array.toString());
				
				
				exClient.sendInstToExcel(inst_array);
		            // Sending "close()" command
	                //conversation.execute("[close()]");
	                // or we can use byte array to send command
	                //conversation.execute("[close()]\0".getBytes());
/*	            }
	            finally
	            {
	                conversation.disconnect();
	            }
*/				
				
				/*
				if(rcvd_str!=null ) {
					System.out.println("length=[" + len + "] " + rcvd_str);
					//synchronized (mySock) {
						String reply_str = reply_cb.reply_func(rcvd_str);
						byte outbuf[] = reply_str.getBytes();
						int outlen = outbuf.length;
						System.out.println("Outgoing msg length=[" + outlen + "] " + reply_str);
						os.writeInt(outlen);
						os.write(outbuf);
					//}
				}
				*/
				System.gc();
			}
		} catch (IOException e) {
			System.err.println("Recv error.");
		}
	}
}

public class JavaClientMain {
	public static Socket clientSocket = null;
	public static int client_id=0;
	public static int getClientId() {
		return client_id;
	}

	public static void main(String[] args) {

		final int DEFAULT_PORT=8800;
		//System.out.println(new String(args[0] + " " + args[1] + " " + args[2] + "length=" + args.length));

		client_id = Integer.parseInt(args[0]);
		String server_ip = (args.length>1)? args[1] : "localhost";
		int port = (args.length>2)? Integer.parseInt(args[2]) : DEFAULT_PORT;
		PrintStream os = null, osSocket=null;

		/*
		 * Open a socket and the input output streams.
		 */
		try {
			System.out.println(new String(server_ip + ":" + port));
			clientSocket = new Socket(server_ip, port);
		} catch (UnknownHostException e) {
			System.err.println("Unknown Host!!");
		} catch (IOException e) {
			System.err.println("Couldn't get I/O for the connection to the host");
		}

		RxThread rx_thread;

		/*
		 * If everything has been initialized then we want to write some data to the socket
		 * we have opened a connection
		 */
		
		if (clientSocket != null) {
			rx_thread = new RxThread(clientSocket, client_id, new ReplyFunc()); 
			rx_thread.start();
		}
	}
}
